import json
from abc import ABC, abstractmethod
from typing import List

import pydantic
from fastapi_pagination.bases import AbstractPage
from fastapi_pagination.ext.databases import paginate
from sqlalchemy import select

from forward.api.pc.schemas.decorate import (
    DecoratePageSchema,
    DecorateTabbarSchema,
    HotSearchSchema,
)
from forward.config import get_settings
from forward.dependencies.database import db
from forward.api.pc.schemas.article import ArticleDetailOutSchema
from forward.api.pc.schemas.article import ArticleSearchOutSchema
from forward.api.pc.schemas.index import (
    IndexOutSchema,
    PolicyInSchema,
    CommonProtocolSchema,
    DecorateOutSchema,
)
from forward.api.pc.schemas.index import SearchInSchema
from forward.model.tables import HotSearchModel
from forward.model.tables.article import ArticleCateGoryModel, ArticleModel
from forward.model.tables.decorate import DecoratePageModel, DecorateTabbarModel
from forward.utils.config import ConfigUtil
from forward.utils.tools import ToolsUtil
from forward.utils.urls import UrlUtil


class IndexService:
    """首页服务实现类"""

    async def index(self):
        """
        首页数据
        :return:
        """
        page_detail_record = await db.fetch_one(
            select(
                DecoratePageModel.id,
                DecoratePageModel.page_type,
                DecoratePageModel.page_data,
            )
            .select_from(DecoratePageModel)
            .where(DecoratePageModel.id == 1)
        )
        assert page_detail_record, "数据不存在！"
        page_detail = DecoratePageSchema.model_validate(
            page_detail_record, from_attributes=True
        )
        pages = json.dumps(
            {
                "id": page_detail.id,
                "page_type": page_detail.page_type,
                "page_data": page_detail.page_data,
            }
        )

        article_query = (
            select(ArticleModel)
            .select_from(ArticleModel)
            .where(ArticleModel.is_delete == 0, ArticleModel.is_show == 1)
            .order_by(ArticleModel.id.desc())
            .limit(20)
        )
        articles_record = await db.fetch_all(article_query)
        articles = [
            ArticleDetailOutSchema.model_validate(article_record, from_attributes=True)
            for article_record in articles_record
        ]
        for article in articles:
            article.image = await UrlUtil.to_absolute_url(article.image)

        domain = UrlUtil.domain
        return {
            "page": {
                "id": 1,
                "type": 1,
                "name": "商城首页",
                "data": '[{"id":"l8ctwzv4r1zl0","title":"搜索","name":"search","disabled":1,"content":{},"styles":{}},{"id":"l8ctwzv455un3","title":"首页轮播图","name":"banner","content":{"enabled":1,"data":[{"image":"uploads/images/20220926/20220926174457333646121.png","name":"11","link":{"path":"/pages/user_data/user_data","name":"个人资料","type":"shop"}}]},"styles":{}},{"id":"l8ctwzv4d0jns","title":"导航菜单","name":"nav","content":{"enabled":1,"data":[{"image":"uploads/images/20220926/20220926174457333646121.png","name":"导航名称","link":{"path":"/pages/news/news","name":"文章资讯","type":"shop"}}]},"styles":{}},{"id":"l8ctwzv4jadxc","title":"资讯","name":"news","disabled":1,"content":{},"styles":{}}]',
                "create_time": "2022-08-29 15:13:08",
                "update_time": "2022-10-11 15:12:51",
            },
            "all": [
                {
                    "id": 2,
                    "title": "测试文章11111",
                    "desc": "123",
                    "abstract": "213",
                    "image": "",
                    "author": "测试123",
                    "create_time": "2022-10-19 10:03:21",
                    "click": 3,
                }
            ],
            "new": [
                {
                    "id": 3,
                    "title": "测试文章222",
                    "desc": "123",
                    "abstract": "12321",
                    "image": "",
                    "author": "测试222",
                    "create_time": "2022-10-19 10:03:40",
                    "click": 0,
                }
            ],
            "hot": [
                {
                    "id": 2,
                    "title": "测试文章11111",
                    "desc": "123",
                    "abstract": "213",
                    "image": "",
                    "author": "测试123",
                    "create_time": "2022-10-19 10:03:21",
                    "click": 3,
                }
            ],
        }
        return IndexOutSchema.model_validate(
            {"domain": domain, "pages": pages, "article": articles}
        )

    async def decorate(self, id_: int) -> dict:
        """装修"""
        page_record = await db.fetch_one(
            select(DecoratePageModel).where(DecoratePageModel.id == id_)
        )
        assert page_record, "数据不存在！"
        return DecorateOutSchema.model_validate(
            page_record, from_attributes=True
        ).model_dump()

    async def config(self, domain) -> dict:
        """配置"""
        # 底部导航
        tabbars_record = await db.fetch_all(
            select(DecorateTabbarModel).order_by(DecorateTabbarModel.id)
        )
        tabbars = [
            DecorateTabbarSchema.model_validate(tabbar_record, from_attributes=True)
            for tabbar_record in tabbars_record
        ]
        tabs = []
        for tab in tabbars:
            tabs.append(
                {
                    "name": tab.name,
                    "selected": await UrlUtil.to_absolute_url(tab.selected),
                    "unselected": await UrlUtil.to_absolute_url(tab.unselected),
                    "link": tab.link,
                }
            )
        # 导航颜色
        tabbar_style = await ConfigUtil.get_val("tabbar", "style", "{}")
        # 登录配置
        login_config = await ConfigUtil.get("login")
        login_map = {
            "loginWay": [
                int(i)
                for i in login_config.get("loginWay", "").split(",")
                if i.isdigit()
            ],
            "forceBindMobile": int(login_config.get("forceBindMobile", "0")),
            "openAgreement": int(login_config.get("openAgreement", "0")),
            "openOtherAuth": int(login_config.get("openOtherAuth", "0")),
            "autoLoginAuth": [
                int(i)
                for i in login_config.get("autoLoginAuth", "").split(",")
                if i.isdigit()
            ],
        }
        # 网址信息
        website_config = await ConfigUtil.get("website")
        website_map = {
            "name": website_config.get("shopName", "forwardAdmin"),
            "logo": await UrlUtil.to_absolute_url(website_config.get("shopLogo", "")),
        }
        # pc配置
        pc_config = await ConfigUtil.get("pc_channel")
        pc_map = {
            "status": int(pc_config.get("status", "0")),
            "close": int(pc_config.get("close", "0")),
            "url": pc_config.get("url", "0"),
            "accessLink": domain,
        }
        copyright = await ConfigUtil.get_val("website", "copyright", "") or ""
        copyright = json.loads(copyright) if copyright else {}
        return {
            "version": get_settings().version,
            "domain": UrlUtil.domain,
            "style": ToolsUtil.json_to_map(tabbar_style) if tabbar_style else {},
            "tabbar": tabs,
            "login": login_map,
            "website": website_map,
            "pc": pc_map,
            "copyright": copyright,
        }

    async def policy(self, policy_in: PolicyInSchema) -> CommonProtocolSchema:
        """
        隐私政策
        :param policy_in:
        :return:
        """
        map = await ConfigUtil.get_map("protocol", policy_in.type)

        return CommonProtocolSchema.model_validate(map, from_attributes=True)

    # async def policy(self, type_: str) -> dict:
    #     """政策"""
    #     policy_dict = await ConfigUtil.get_map('protocol', type_)
    #     if not policy_dict:
    #         return {'name': '', 'content': ''}
    #     return policy_dict

    async def hot_search(self) -> List[str]:
        """热搜"""
        is_hot_search = await ConfigUtil.get_val("search", "isHotSearch", "0")
        names = []
        if is_hot_search == "1":
            hot_search_records = await db.fetch_all(
                select(HotSearchModel).order_by(
                    HotSearchModel.sort.desc(), HotSearchModel.id.desc()
                )
            )
            hot_searchs = [
                HotSearchSchema.model_validate(hot_search_record)
                for hot_search_record in hot_search_records
            ]
            for hot_search in hot_searchs:
                names.append(hot_search.name)
        return names

    async def search(
        self, search_in: SearchInSchema
    ) -> AbstractPage[ArticleSearchOutSchema]:
        """搜索"""
        query = (
            select(ArticleModel, ArticleCateGoryModel.name.label("category"))
            .select_from(ArticleModel)
            .outerjoin(
                ArticleCateGoryModel, ArticleModel.cid == ArticleCateGoryModel.id
            )
            .where(
                ArticleModel.is_delete == 0,
                ArticleModel.title.like(f"%{search_in.keyword}%"),
            )
            .order_by(ArticleModel.sort.desc(), ArticleModel.id.desc())
        )
        pager = await paginate(db, query)
        for row in pager.lists:
            row.collect = False
            row.image = await UrlUtil.to_absolute_url(row.image)
        return pager

    @classmethod
    async def instance(cls):
        """实例化"""
        return cls()
